#include "OgreRoot.h"
#include "OgreException.h"
#include "OgreLogManager.h"
#include "OgreStringConverter.h"
#include "OgreWindowEventUtilities.h"

#include "OgreGLESPrequisites.h"
#include "OgreGLESRenderSystem.h"

#include "OgreSymbianEGLSupport.h"
#include "OgreSymbianEGLWindow.h"
#include "OgreSymbianEGLContext.h"

#include <iostream>
#include <algorithm>
#include <climits>
#include <w32std.h>
#include <coemain.h>
namespace Ogre
{
	SymbianEGLWindow::SymbianEGLWindow(EGLSupport* glsupport)
		: EGLWindow(glsupport), mNativeControl(NULL)
	{
	}
	
	SymbianEGLWindow::~SymbianEGLWindow()
	{
		if (mIsExternal && mWindow != NULL)
		{
			((RWindow*)mWindow)->SetOrdinalPosition(KOrdinalPositionSwitchToOwningWindow);
			((RWindow*)mWindow)->Close();
			delete mWindow;
			mWindow = NULL;
		}
	}
	
	EGLContext* SymbianEGLWindow::createEGLContext() const
	{
		return new SymbianEGLContext(mEglDisplay, mGLSupport, mEglConfig, mEglSurface);
	}
	
	void SymbianEGLWindow::getLeftAndTopFromNativeWindow(int& left, int& top, uint width, uint height)
	{
	}
	
	void SymbianEGLWindow::initNativeCreatedWindow(const NameValuePairList *miscParams)
	{
	}
	
	void SymbianEGLWindow::createNativeWindow(int& left, int& top, uint& width, uint& height, String& title)
	{
		if (!mIsExternal)
		{
			if (mWindow)
			{
				destroy();
			}
		}
		
		mClosed = false;
		mColourDepth = 32;
		
		if (!mIsExternal)
		{
			mWindow = 0;
			
			RWsSession iWsSession;
			RWindowGroup iWindowGroup;
			
			CWsScreenDevice* iWsScreenDevice;
			
			CCoeEnv* env = CCoeEnv::Static();
			iWsSession = env->WsSession();
			iWsScreenDevice = env->ScreenDevice();
			iWindowGroup = env->RootWin();
			
			{
				CCoeEnv* env = CCoeEnv::Static();
				RWsSession iWsSession;
				RWindowGroup iWindowGroup;
				CWsScreenDevice* iWsScreenDevice;
				iWsSession = env->WsSession();
				iWsScreenDevice = env->ScreenDevice();
				iWindowGroup = env->RootWin();
				
				if (!iWsScreenDevice)
				{
					return;
				}
				
				RWindow* iWindow;
				iWindow = new (Eleave)RWindow(iWsSession);
				
				TInt err2 = iWindow->Construct(iWindowGroup,
					435353,
					);
				User::LeaveIfError(err2);
				
				iWindowGroup.EnableScreenChangeEvents();
				
				TPixelsTwipsAndRotation pixnrot;
				iWsScreenDevice->GetScreenModeSizeAndRotation(
					iWsScreenDevice->CurrentScreenMode(),
					pixnrot);
					
				iWindow->SetExtent(TPoint(0, 0),
					pixnrot.iPixelSize);
					
				iWindow->SetRequiredDisplayMode(iWsScreenDevice->DisplayMode());
				
				iWindow->Activate();
				iWindow->SetVisible(ETrue);
				iWindow->SetNonFading(ETrue);
				iWindow->SetShadowDisabled(ETrue);
				iWindow->EnableRedrawStore(EFalse);
				iWindow->EnableVisibilityChangeEvents();
				iWindow->SetNonTransparent();
				iWindow->SetBackgroundColor();
				iWindow->SetOrdinalPosition(0);
				mWindow = iWindow;
			}
		}
		
		mNativeDisplay = EGL_DEFAULT_DISPLAY;
		mEglDisplay = eglGetDisplay(mNativeDisplay);
		mGLSupport->setGLDisplay(mEglDisplay);
		
		TDisplayMode displayMode = ((RWindow*)mWindow)->DisplayMode();
		TInt bufferSize = 0;
		
		switch(displayMode)
		{
			case (EColor4K):
				bufferSize = 12;
				break;
			case (EColor64K):
				bufferSize = 16;
				break;
			case (EColor16M):
				bufferSize = 24;
				break;
			case (EColor16MU):
			case (EColor16MA):
				bufferSize = 32;
				break;
			default:
				break;
		}
		
		const EGLint attributeList[] = {
			EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
			EGL_BUFFER_SIZE, bufferSize,
			EGL_NONE};
			
		EGLint numConfigs = 0;
		
		if (eglChooseConfig(mEglDisplay, attributeList, &mEglConfig,
			1, &numConfigs) == EGL_FALSE)
		{
			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
				"eglChooseConfig failed(== EGL_FALSE)!\n",
				__FUNCTION__);
		}
		
		if (numConfigs == 0)
		{
			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
				"eglChooseConfig failed (numConfigs == 0)!\n",
				__FUNCTION__);
		}
		
		mEglSurface = createSurfaceFromWindow(mEglDisplay, mWindow);
	}
	
	void SymbianEGLWindow::reposition(int left, int top)
	{
	}
	
	void SymbianEGLWindow::resize(unsigned int width, unsigned int height)
	{
		if (!mNativeControl || !mWindow)
			return;
			
		mWidth = width;
		mHeight = height;
		
		ViewportList::iterator it, itend;
		itend = mViewportList.end();
		for (it = mViewportList.begin(); it != itend; ++it)
			(*it).second->updateDimensions();
	}
	
	void SymbianEGLWindow::windowMoveOrResized()
	{
		resize(mNativeControl->size().iWidth, mNativeControl->Size().iHeight);
	}
	
	void SymbianEGLWindow::switchFullscreen(bool fullscreen)
	{
	}
	
	void SymbianEGLWindow::create(const String& name, unsigned int width, unsigned int height, bool fullScreen, const NameValuePairList *miscParams)
	{
		String title = name;
		uint samples = 0;
		int gamma;
		short frequency = 0;
		bool vsync = false;
		::EGLContext eglContext = 0;
		int left = 0;
		int top = 0;
		
		mIsExternal = false;
		
		mIsFullScreen = fullScreen;
		
		if (miscParams)
		{
			NameValuePairList::const_iterator opt;
			NameValuePairList::const_iterator end = miscParams->end();
			
			if ((opt = miscParams->find("NativeWindow")) != end)
			{
				mWindow = (NativeWindowType)StringConverter::parseUnsignedLong(opt->second);
			}
			
			if ((opt = miscParams->find("NativeControl")) != end)
			{
				mIsExternal = true;
				mNativeControl = (CCoeControl*)StringConverter::parseUnsignedLong(opt->second);
				eglContext = eglGetCurrentContext();
				if (eglContext)
				{
					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
							"currentGLContext was specified with no current GL context",
							"EGLWindow::create");
				}
				
				eglContext = eglGetCurrentContext();
			}
			
			if ((opt = miscParams->find("FSAA")) != end)
			{
				samples = StringConverter::parseUnsignedInt(opt->second);
			}
			
			if ((opt = miscParams->find("displayFrequency")) != end)
			{
				frequency = (short)StringConverter::parseInt(opt->second);
			}
			
			if ((opt = miscParams->find("vsync")) != end)
			{
				vsync = StringConverter::parseBool(opt->second);
			}
			
			if ((opt = miscParams->find("gamma")) != end)
			{
				gamma = StringConverter::parseBool(opt->second);
			}
			
			if ((opt = miscParams->find("left")) != end)
			{
				left = StringConverter::parseInt(opt->second);
			}
			
			if ((opt = miscParams->find("top")) != end)
			{
				top = StringConverter::parseInt(opt->second);
			}
			
			if ((opt = miscParams->find("title")) != end)
			{
				title = opt->second;
			}
			
			if ((opt = miscParams->find("externalGLControl")) != end)
			{
				mIsExternalGLControl = StringConverter::parseBool(opt->second);
			}
		}
		
		initNativeCreatedWindow(miscParams);
		
		if (mEglSurface)
		{
			mEglConfig = mGLSupport->getGLConfigFromDrawable(mEglSurface, &width, &height);
		}
		
		if (!mEglConfig && eglContext)
		{
			mEglConfig = mGLSupport->getGLConfigFromContext(eglContext);
			
			if (mEglConfig)
			{
				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
					"Unexpected failure to determine a EGLFBConfig",
					"EGLWindow::create");
			}
		}
		
		if (!mIsTopLevel)
		{
			mIsFullScreen = false;
			left = top = 0;
		}
		
		if (mIsFullScreen)
		{
			mGLSupport->switchMode(width, height, frequency);
		}
		
		createNativeWindow(left, top, width, height title);
		
		mContext = createEGLContext();
		
		::EGLSurface oldDrawableDraw = eglGetCurrentSurface(EGL_DRAW);
		::EGLSurface oldDrawableRead = elgGetCurrentSurface(EGL_READ);
		::EGLContext oldContext = eglGetCurrentContext();
		
		EGLint glConfigID;
		
		mGLSupport->getGLConfigAttrib(mEglConfig, EGL_CONFIG_ID, &glConfigID);
		LogManager::getSingleton().logMessage("EGLWindow::create used FBConfigID = " + StringConverter::toString(glConfigID));
		
		mName = name;
		mWidth = width;
		mHeight = height;
		mLeft = left;
		mTop = top;
		mActive = true;
		mVisible = true;
		
		mClosed = false;
	}
	
	void SymbianEGLWindow::getCustomAttribute(const String& name, void* pData)
	{
		if (name == "CONTROL")
		{
			*static_cast<CCoeControl**>(pData) = mNativeControl;
		}
		
		EGLWindow::getCustomAttribute(name, pData);
	}
}
